package imai78gae.heya.service.impl;

import java.util.List;

import imai78gae.heya.exception.ResourceNotFoundException;
import imai78gae.heya.model.Group;
import imai78gae.heya.model.Message;
import imai78gae.heya.model.UserInfo;
import imai78gae.heya.service.GroupService;
import imai78gae.heya.util.MailUtil;
import imai78gae.heya.util.ModelCopyUtil;
import imai78gae.heya.util.PMF;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

/**
 * {@link GroupService}の実装です。
 * 
 * @author imai78
 *
 */
public class GroupServiceImpl implements GroupService {

	/**
	 * {@inheritDoc}
	 */
	public void addMessage(String groupId, Message message) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Group gr = this.getGroup(groupId);
		gr.getMessages().add(0, message);
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			pm.makePersistent(gr);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void createNewGroup(String groupId, String groupName,
			String groupDescription, String inviteKey,
			String groupOwnerId, String groupOwnerName) {
		Group group = new Group(
				groupId, groupName, groupDescription, inviteKey,
				groupOwnerId, groupOwnerName);
		this.createNewGroup(group);
	}

	/**
	 * {@link Group}を新規オブジェクトとして登録します。
	 * 
	 * @param group 新規登録する{@link Group}オブジェクト
	 */
	void createNewGroup(Group group) {
		group.setGroupKey(null);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			pm.makePersistent(group);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public Group getGroup(String groupId) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Group result = this.getGroup(pm, groupId);
		pm.close();
		return result;
	}

	/**
	 * 指定されたグループIDを持つグループを返します。
	 * 
	 * @param pm {@link PersistenceManager}オブジェクト
	 * @param groupId 取得したいグループのグループID
	 * @return グループ
	 */
	@SuppressWarnings("unchecked")
	Group getGroup(PersistenceManager pm, String groupId) {
		Query query = pm.newQuery(Group.class);
		query.setFilter("groupId == groupIdParam");
		query.declareParameters("String groupIdParam");
		List<Group> list = (List<Group>) query.execute(groupId);
		if (list.size() == 0) {
			throw new ResourceNotFoundException("Group is not found.");
		}
		return list.get(0);
	}

	/**
	 * {@inheritDoc}
	 */
	public List<Message> getGroupMessages(String groupId) {
		Group group = this.getGroup(groupId);
		return group.getMessages();
	}

	/**
	 * {@inheritDoc}
	 */
	public void inviteUser(String groupId, String userName, String targetMailAddress) {
		Group group = this.getGroup(groupId);
		MailUtil.sendInviteMail(group, userName, targetMailAddress);
	}

	/**
	 * {@inheritDoc}
	 */
	public void joinUser(String groupId, UserInfo userInfo) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			Group group = this.getGroup(pm, groupId);
			group.getMemberLoginIdList().add(userInfo.getLoginId());
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void removeEmergency(String groupId) {
		Group newGroup;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			Group oldGroup = this.getGroup(pm, groupId);
			newGroup = ModelCopyUtil.copyGroup(oldGroup, false);
			pm.deletePersistent(oldGroup);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
		this.createNewGroup(newGroup);
	}

	/**
	 * {@inheritDoc}
	 */
	public void removeMessage(String groupId, String messageId) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			Message message = this.getMessage(pm, groupId, messageId);
			pm.deletePersistent(message);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * 指定されたグループに従属する
	 * 指定されたメッセージIDを持つ{@link Message}を返します。
	 * 
	 * @param pm {@link PersistenceManager}オブジェクト
	 * @param groupId 対象のグループのグループID
	 * @param messageId 対象のメッセージID
	 * @return 指定した{@link Message}オブジェクト
	 */
	Message getMessage(PersistenceManager pm, String groupId, String messageId) {
		Group group = this.getGroup(pm, groupId);
		List<Message> list = group.getMessages();
		for (Message msg : list) {
			if (messageId.equals(msg.getMessageId())) {
				return msg;
			}
		}
		return null;
	}

}
